{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Примерное содержание первого семестра:\n",
    "\n",
    "От исходного кода до исполняемого файла:\n",
    "* что есть программа на С++\n",
    "* процесс сборки \n",
    "* компилятор и некоторые его опции\n",
    "\n",
    "Свойства языка:\n",
    "* функции и операторы\n",
    "* классы\n",
    "* шаблоны\n",
    "* исключения\n",
    "* умные указатели\n",
    "* стандартные контейнеры и алгоритмы\n",
    "* лямбда-функции\n",
    "\n",
    "Практики разработки:\n",
    "* экосистема С++ проектов\n",
    "* практики производительности\n",
    "* юнит-тестирование: как и чем"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Что хотелось бы преподать в рамках курса:**\n",
    "* Основы языка с разбором механизмов. Не только что есть в языке, но и как оно работает.\n",
    "* Общие практики программирования (тестирование, разделение ответственности, упрощение ...).\n",
    "* Стиль С++."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Лекция 1. Введение"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Обзор места языка на рынке\n",
    "\n",
    "* Зачем С++? Почему не язык X?\n",
    "    * Высокоуровневый язык с прямым отображением программы на железо\n",
    "        * нет прослойки типа виртуальной машины или интерпретатора\n",
    "        * C++ vs Python?\n",
    "        * С++ vs Java?\n",
    "    * Программист по умолчанию умный\n",
    "        * на момент создания языка - да\n",
    "        * в 2020-х - нет\n",
    "* Какова ниша С++?\n",
    "    * Примеры областей для использования:\n",
    "        * Игровые движки\n",
    "        * Физические движки\n",
    "        * Браузеры\n",
    "        * Компиляторы\n",
    "        * Backend\n",
    "        * ОС\n",
    "        * Математические пакеты\n",
    "        * HPC\n",
    "        * ...\n",
    "    * Что их объединяет?\n",
    "* Альтернативы на его нише?\n",
    "    * Rust\n",
    "        * создан на 30 лет позже С++\n",
    "        * учтён главный недостаток С++: программист по умолчанию больше не умный\n",
    "        * свободен от проблем обратной совместимости... пока что"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Замечание:** вопреки распространённому мнению, С++ уже не является \"надмножеством\" на языком С. Не каждая программа на языке С корректна для С++ (даже не учитывая простейших вещей типа новых ключевых слов). Стандарты С++ и С разошлись со временем. Неполный список расхождений [по стандарту](http://eel.is/c++draft/diff.iso), [по стандартной библиотеке](http://eel.is/c++draft/diff.library)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Замечание:** Показать страницу курса, рассказать про домашние задания, оценки и способ взаимодействия если ещё не."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Запускаем Hello world"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hello world на С++ и что есть что.\n",
    "\n",
    "(что будет, если убрать каждый из элементов?)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <cstdio>\n",
    "\n",
    "int main()\n",
    "{\n",
    "    std::puts(\"Hello world\");\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "От текста программы к исполняемому файлу. Зачем нужен компилятор."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#include <cstdio>\r\n",
      "\r\n",
      "int main()\r\n",
      "{\r\n",
      "    std::puts(\"Hello world\");\r\n",
      "    return 0;\r\n",
      "}\r\n",
      "\r\n"
     ]
    }
   ],
   "source": [
    "!cat hello_world.cpp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Шаг 1: компилятор преобразует файл программы на С++ в объектный файл - скомпилированный набор функций файла в виде инструкций ассемблера и констант"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "!clang++ -c -O3 hello_world.cpp -o hello_world.o"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`hello_world.o` содержит в бинарном виде код функций cpp-файла, константы и прочую вспомогательную информацию. Более подробно с его содержимым будем знакомиться ближе к концу курса."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Шаг 2: линковщик собирает несколько объектных файлов в один исполняемый"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "!clang++ -O3 hello_world.o -o hello_world.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Запустим:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello world\r\n"
     ]
    }
   ],
   "source": [
    "!./hello_world.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Итого:**\n",
    "\n",
    "```\n",
    "Исходный код\n",
    "    -- (компилятор) --> объектные файлы\n",
    "    -- (линковщик)  --> исполняемый файл\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Замечание:**\n",
    "\n",
    "Для маленьких программ можно пропустить промежуточный этап с объектными файлами, сразу сгенерировав исполяемый файл:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# нет опции \"-c\":\n",
    "!clang++ -O3 hello_world.cpp -o hello_world.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Вопрос:**\n",
    "\n",
    "Как переход от текста программы к её исполнению устроен в Java?  В Python?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Базовые типы данных"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// https://en.cppreference.com/w/cpp/language/types\n",
    "\n",
    "int main()\n",
    "{\n",
    "    //\n",
    "    // boolean\n",
    "    //\n",
    "    bool b = true;\n",
    "    \n",
    "    //\n",
    "    // integer\n",
    "    //\n",
    "\n",
    "    // >= 16 byte\n",
    "    short s = 0;\n",
    "    unsigned short us = 0;\n",
    "        \n",
    "    // >= 16 byte\n",
    "    int x = 0;\n",
    "    unsigned int ux = 0;\n",
    "        \n",
    "    // >= 32 byte\n",
    "    long l = 0;\n",
    "    unsinged long ul = 0;\n",
    "\n",
    "    // >= 64 byte\n",
    "    long long ll = 0;\n",
    "    unsigned long long ull = 0;\n",
    "\n",
    "    std::int32_t i32 = 0;\n",
    "    std::int64_t i64 = 0;\n",
    "    std::uint32_t u32 = 0;\n",
    "    std::uint64_t u64 = 0;\n",
    "\n",
    "    //\n",
    "    // chars\n",
    "    //\n",
    "    char c = 0;\n",
    "    unsinged uc = 0;\n",
    "\n",
    "    std::char16_t c16 = 0;\n",
    "    std::char32_t c32 = 0;\n",
    "    \n",
    "    // 1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)\n",
    "    \n",
    "    //\n",
    "    // floats\n",
    "    //\n",
    "    float f = 0.f;        // usually 32-bit IEEE-754 type\n",
    "    double d = 0.;        // usually 64-bit IEEE-754 type\n",
    "    long double ld = 0.;  // usually 80-bit\n",
    "    \n",
    "    //\n",
    "    // pointers\n",
    "    //\n",
    "    int x = 3;\n",
    "    int y = 4;\n",
    "    int* p = nullptr;  // указатель на значение типа int\n",
    "    \n",
    "    p = &x;\n",
    "    *p = 5;  // теперь x == 5\n",
    "    p = &y;\n",
    "    *p = 6;  // теперь y == 6\n",
    "    p = nullptr;\n",
    "    *p = 7;  // ошибка\n",
    "\n",
    "    //\n",
    "    // c-style arrays:\n",
    "    //\n",
    "    int x[3] = {0, 1, 2};  // size must be known at compile time\n",
    "    x[2] = 5;\n",
    "    x[3] = 6;  // ooops\n",
    "    std::cout << \"x elements count = \" << std::size(x) << std::endl;\n",
    "\n",
    "    int y[] = {0, 1, 2};  // autodetect size at compile time\n",
    "    std::cout << \"y elements count = \" << std::size(y) << std::endl;\n",
    "\n",
    "    //\n",
    "    // c-style strings and pointers:\n",
    "    //\n",
    "    const char name[] = \"Petr\";  // array of symbols\n",
    "    std::cout << \"name length = \" << std::size(name) << std::endl;  // ?\n",
    "\n",
    "    const char *name2 = \"Petr\";  // pointer\n",
    "    // std::size(name2) вызвать нельзя, т.е. name2 - указатель\n",
    "    // вопрос: как узнать размер строки?\n",
    "\n",
    "    name2[0];  // P\n",
    "    name2[1];  // e\n",
    "    name2[2];  // t\n",
    "\n",
    "    *name2;        // P\n",
    "    *(name2 + 1);  // e\n",
    "    *(name2 + 2);  // t\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Пределы представления чисел:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// https://en.cppreference.com/w/cpp/types/numeric_limits\n",
    "    \n",
    "#include <numeric_limits>\n",
    "    \n",
    "std::numeric_limits<std::int32_t>::max()\n",
    "std::numeric_limits<std::int64_t>::min()\n",
    "    \n",
    "std::numeric_limits<float>::max()\n",
    "std::numeric_limits<float>::min()\n",
    "std::numeric_limits<float>::lowest()\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###### Управляющие конструкции языка: `if-else`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Стандартная комбинация блоков `if-else`:\n",
    "\n",
    "```c++\n",
    "if (x % 2 == 0)\n",
    "{\n",
    "    std::puts(\"x is even\");\n",
    "}\n",
    "else\n",
    "{\n",
    "    std::puts(\"x is odd\");\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Блок `else` может быть опущен:\n",
    "\n",
    "```c++\n",
    "if (x % 2 == 0)\n",
    "{\n",
    "    std::puts(\"x is even\");\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В случае блока из одной операции скобки для краткости можно опускать:\n",
    "    \n",
    "```c++\n",
    "if (x % 2 == 0)\n",
    "    std::puts(\"x is even\");\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вычисления в условии:\n",
    "\n",
    "```c++\n",
    "if (int x = some_number())\n",
    "{\n",
    "    ... // do something with x != 0\n",
    "}\n",
    "\n",
    "if (int x = some_number(); x >= 5)\n",
    "{\n",
    "    ... // do something with x >= 5\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###### Управляющие конструкции языка: циклы"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "// for loop\n",
    "for (int i = 0; i < 100; ++i)\n",
    "{\n",
    "    ...\n",
    "}\n",
    "\n",
    "// range for\n",
    "std::vector<int> v = {10, 20, 30, 40, 50};\n",
    "for (int i : v)\n",
    "{\n",
    "    ...\n",
    "}\n",
    "\n",
    "// while\n",
    "while (exression)\n",
    "{\n",
    "    ...\n",
    "}\n",
    "\n",
    "// do-while\n",
    "do\n",
    "{\n",
    "    ...\n",
    "}\n",
    "while (expression);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Область видимости объектов"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Область видимости _объявляемого_ объекта (переменной) ограничена блоком, в котором переменная определена.\n",
    "\n",
    "```c++\n",
    "{\n",
    "    ...;\n",
    "    int x = 5;\n",
    "    ...;\n",
    "}  // здесь заканчивается область видимости переменной x\n",
    "\n",
    "// здесь обращение к x невозможно\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Пример**:\n",
    "\n",
    "Предуперить студента, что он набрал слишком много курсов\n",
    "    \n",
    "```c++\n",
    "if (classes_count > 3)\n",
    "{\n",
    "    int excessive_count = classes_count - 3;\n",
    "    std::cout << \"too many classes, consider to leave: \"\n",
    "              << excessive_count\n",
    "              << std::endl;\n",
    "}\n",
    "// excessive_count после if недоступен, значение утеряно\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Пример** с переопределением:\n",
    "    \n",
    "```c++\n",
    "{\n",
    "    int x = 5;\n",
    "    \n",
    "    {\n",
    "        int x = 7;  // другая переменная с совпадающим именем\n",
    "                    // обратиться к прежнему x по имени нельзя\n",
    "        ...\n",
    "    }\n",
    "    \n",
    "    std::cout << x << std::endl;  // 5\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Область видимости _временного_ объекта ограничена выражением, в рамках которого временный объект появляется.\n",
    "\n",
    "```c++\n",
    "bool is_even(int x);\n",
    "\n",
    "bool is_sum_even(int x, int y)\n",
    "{\n",
    "    bool result = is_even(x + y);   // результат x + y живёт до ;\n",
    "    return result;                  // здесь объект (x + y) уже мёртв\n",
    "}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Стек и куча"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![img](stack_and_heap.png \"Стек и куча\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_(здесь нужно в zoom рисовать как отматывается стэк и что где лежит)_\n",
    "\n",
    "```c++\n",
    "void my_function()\n",
    "{\n",
    "    int x = 500;  // value on stack\n",
    "    int *p = &x;  // pointer to value (что такое указатель?)\n",
    "    \n",
    "    *p = 42;\n",
    "    std::cout << x;  // ??\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Размотка стека при вызове функции (упрощённый вариант):\n",
    "\n",
    "_(здесь нужно в zoom рисовать как отматывается стэк и что где лежит)_\n",
    "\n",
    "```c++\n",
    "void make_floor()\n",
    "{\n",
    "    float side = 3.f;\n",
    "    float height = 0.2f; /* ... */\n",
    "}\n",
    "\n",
    "void make_wall()\n",
    "{\n",
    "    float height = 3.f;\n",
    "    float width = 0.2f; /* ...; */\n",
    "}\n",
    "\n",
    "void build_house()\n",
    "{\n",
    "    int price = 100500;\n",
    "    make_floor();\n",
    "    make_wall();\n",
    "    make_wall();\n",
    "    std::cout << \"your bill: \" << price << std::endl;\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    build_house();\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Куча (heap):"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Размер памяти, отводимый под стек, должен быть известен на этапе компиляции.\n",
    "\n",
    "Но это не достижимо для всех задач. Например, при чтении таблицы студентов из базы данных, мы во время компиляции не можем сказать, сколько памяти нужно под таблицу. Вопрос должен решаться отложенно, во время выполнения. Для этого существует механизм \"кучи\"."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "_(здесь нужно в zoom рисовать как отматывается стэк и что где лежит)_\n",
    "\n",
    "```c++\n",
    "void my_function()\n",
    "{\n",
    "    int *p = (int *)malloc(sizeof(int));  // pointer to value on heap\n",
    "    *p = 500;\n",
    "    int x = *p;                    // value on stack\n",
    "\n",
    "    *p = 42;\n",
    "    std::cout << x;  // ??\n",
    "    \n",
    "    free(p);\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача**: найдите ошибку\n",
    "\n",
    "```c++\n",
    "// функция возвращает указатель на ячейку памяти,\n",
    "// где лежит цена дома\n",
    "int* get_house_price()\n",
    "{\n",
    "    int price = 100500;\n",
    "    return &price;\n",
    "}\n",
    "\n",
    "int main()\n",
    "{\n",
    "    int *p = get_house_price();\n",
    "    std::cout << \"your bill: \" << *p << std::endl;\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### C / C++  строки"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "//\n",
    "// С-строки\n",
    "//\n",
    "// функции стандартной библиотеки для работы со строками в стиле С\n",
    "// https://en.cppreference.com/w/cpp/string/byte\n",
    "\n",
    "const char* cname = \"cpushkin\";  // where? len?\n",
    "std::cout << cname << std::endl;\n",
    "\n",
    "char* pcname = (char*)malloc(sizeof(char) * (strlen(cname) + 1));  // where? +1?\n",
    "strcpy(pcname, cname);\n",
    "std::cout << pcname << std::endl;\n",
    "free(pcname);\n",
    "\n",
    "const char* greeting = \"Ai da \" + cname; // ! ERROR\n",
    "\n",
    "char s[100];\n",
    "sprintf(s, \"%i\", 42);\n",
    "\n",
    "\n",
    "//\n",
    "// C++ - строки\n",
    "//\n",
    "// класс стандартной строки:\n",
    "// https://en.cppreference.com/w/cpp/string/basic_string\n",
    "//\n",
    "// функции конвертации строк:\n",
    "// https://en.cppreference.com/w/cpp/string/basic_string/to_string\n",
    "\n",
    "std::string cppname = \"cpppushkin\";\n",
    "std::cout << cppname << std::endl;\n",
    "                \n",
    "std::string prep = \"Ai da\";\n",
    "std::string greeting = prep + \" \" + cppname; // OK\n",
    "        \n",
    "std::string s = std::to_string(42);\n",
    "\n",
    "std::string* pcppname = &cppname; // what is it?\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Функции"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Напишем функцию, вычисляющую длину двумерного вектора:\n",
    "\n",
    "Подробно рассказать что есть что в этом коде."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float length(float x, float y)\n",
    "{\n",
    "    float sqrLength = x * x + y * y;\n",
    "    return std::sqrt(sqrLength);\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вызов функции:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "float len = length(3.f, 4.f);\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Если функция не должна ничего возвращать, есть специально зарезервированное слово `void`:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "void log_person_arrived_to_airport(const char* name)\n",
    "{\n",
    "    ...\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Передача аргументов в функцию"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "По значению:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "void f(int n)\n",
    "{\n",
    "    ++n;\n",
    "    std::clog << n << std::endl;\n",
    "}\n",
    "\n",
    "\n",
    "x = 3;\n",
    "f(x);  // 4\n",
    "std::cout << x << std::endl;  // 3\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "По ссылке:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "void f(int& n)\n",
    "{\n",
    "    ++n;\n",
    "    std::clog << n << std::endl;\n",
    "}\n",
    "\n",
    "\n",
    "x = 3;\n",
    "f(x);  // 4\n",
    "std::cout << x << std::endl;  // 4\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вариант - по константной ссылке:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "void f(const int& n)\n",
    "{\n",
    "    ++n;  // COMPILER ERROR!\n",
    "    std::clog << n << std::endl;\n",
    "}\n",
    "\n",
    "\n",
    "x = 3;\n",
    "f(x);\n",
    "std::cout << x << std::endl;\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "В каком случае лучше передвать по значению, а когда по ссылке?\n",
    "* дешёвые для копирования объекты - по значению\n",
    "* дорогие для копирования объекты - по ссылке"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Рассмотрим разницу:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string get_full_name(const std::string& name, const std::string& surname)\n",
    "{\n",
    "    return name + \" \" + surname;\n",
    "}\n",
    "\n",
    "std::string get_full_name(std::string name, std::string surname)\n",
    "{\n",
    "    return name + \" \" + surname;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "А если так, в чём проблема?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string get_full_name(std::string& name, std::string& surname)\n",
    "{\n",
    "    return name + \" \" + surname;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "А что происходит здесь?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "std::string get_full_name(std::string *name, std::string *surname)\n",
    "{\n",
    "    return *name + \" \" + *surname;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Ввод-вывод средствами С и C++"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача**: посчитать сумму 500 000 целых чисел из потока ввода.\n",
    "\n",
    "Решим эту задачу средствами С и С++ и оценим различия в подходах."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сгенерируем тестовые данные:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('input.txt', 'w') as f:\n",
    "    f.write(' '.join(['1'] * 500000))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Решение задачи с использованием средства ввода-вывода С:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <cstdio>\n",
    "\n",
    "int main()\n",
    "{\n",
    "    int sum = 0;\n",
    "    for (int i = 0; i < 500'000; ++i)\n",
    "    {\n",
    "        int x = 0;\n",
    "        std::scanf(\"%i\", &x);\n",
    "        sum += x;\n",
    "    }\n",
    "    std::printf(\"%i\\n\", sum);\n",
    "    return 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Со спецификацией форматов можно ознакомиться [здесь](https://en.cppreference.com/w/cpp/io/c/fprintf)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Решение задачи с использованием средства ввода-вывода С++:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <iostream>\n",
    "\n",
    "\n",
    "int main()\n",
    "{\n",
    "\tint sum = 0;\n",
    "\tfor (int i = 0; i < 500'000; ++i)\n",
    "\t{\n",
    "\t\tint x = 0;\n",
    "\t\tstd::cin >> x;\n",
    "\t\tsum += x;\n",
    "\t}\n",
    "\tstd::cout << sum << std::endl;\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скомпилируем решения:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)\r\n",
      "Target: x86_64-pc-linux-gnu\r\n",
      "Thread model: posix\r\n",
      "InstalledDir: /usr/bin\r\n"
     ]
    }
   ],
   "source": [
    "!clang++ --version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.08\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 main_c.cpp -o inout_c.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.28\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" clang++ -O3 main_cpp.cpp -o inout_cpp.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Проверим размеры исполняемых файлов"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-rwxrwxr-x 1 ivafanas ivafanas 8240 июл 29 22:52 inout_c.exe\r\n",
      "-rwxrwxr-x 1 ivafanas ivafanas 8880 июл 29 22:52 inout_cpp.exe\r\n"
     ]
    }
   ],
   "source": [
    "!ls -l *.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Зайдём на godbolt.org и посмотрим на причину, почему исполняемый файл для С++ - решения стал шире"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Запустим, проверим, какое работает быстрее"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.02\r\n",
      "500000\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" cat input.txt | ./inout_c.exe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "execution time: 0:00.05\r\n",
      "500000\r\n"
     ]
    }
   ],
   "source": [
    "!time -f \"execution time: %E\" cat input.txt | ./inout_cpp.exe"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Вопросы для обсуждения:\n",
    "* Почему?\n",
    "* Всегда ли решение в стиле С работает быстрее?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Сравнение:\n",
    "\n",
    "С:\n",
    "* быстрая компиляция\n",
    "* быстрое выполнение\n",
    "* меньше размер исходного файла\n",
    "\n",
    "C++:\n",
    "* типобезопасно\n",
    "\n",
    "  ```c++\n",
    "  scanf(**\"%i\"**, &i);\n",
    "  ```\n",
    "\n",
    "\n",
    "* меньше ошибок при множественной записи / чтении:\n",
    "  ```c++\n",
    "  printf(\"%i %f %u\", i, z, n);\n",
    "  std::cout << i << ' ' << z << ' ' << n;\n",
    "  ```\n",
    "\n",
    "* меньше ошибок с адресной арифметикой\n",
    "\n",
    "  ```c++\n",
    "  scanf(\"%i\", **&**i);\n",
    "  ```\n",
    "\n",
    "\n",
    "<br />\n",
    "\n",
    "**Вывод**: если программа упирается в ввод-вывод - используем С - вариант, если нет - С++ - вариант."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Работа с командной строкой"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Общепринят формат передачи аргументов командной строки в программу, в котором аргументы делятся на:\n",
    "* позиционные\n",
    "* флажки\n",
    "* именованные со значением\n",
    "\n",
    "Пример программы `ls`, выводящей содержимое папки:\n",
    "\n",
    "```\n",
    "ls /usr/bin -a --human-readable --color=always\n",
    "ls -a --color always --human-readable /usr/bin\n",
    "```\n",
    "\n",
    "описание опций можно прочитать, набрав `ls --help`:\n",
    "\n",
    "```\n",
    "  -a, --all                  do not ignore entries starting with .\n",
    "  -h, --human-readable       with -l and/or -s, print human readable sizes\n",
    "                               (e.g., 1K 234M 2G)\n",
    "      --color[=WHEN]         colorize the output; WHEN can be 'always' (default\n",
    "                               if omitted), 'auto', or 'never'; more info below\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Задача**: вывести аргументы командной строки, переданные консольной утилите"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```c++\n",
    "#include <iostream>\n",
    "\n",
    "\n",
    "int main(int argc, char** argv)\n",
    "{\n",
    "\tstd::cout << \"command line arguments are:\" << std::endl;\n",
    "\tfor (int i = 0; i < argc; ++i)\n",
    "\t{\n",
    "\t\tstd::cout << \"    \" << i << \" -> \" << argv[i] << std::endl;\n",
    "\t}\n",
    "\treturn 0;\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Скомпилируем"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "!clang++ -O3 main.cpp -o a.out"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Протестируем"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "command line arguments are:\r\n",
      "    0 -> ./a.out\r\n",
      "    1 -> /usr/bin\r\n",
      "    2 -> -a\r\n",
      "    3 -> --human-readable\r\n",
      "    4 -> --color=always\r\n"
     ]
    }
   ],
   "source": [
    "!./a.out /usr/bin -a --human-readable --color=always"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "command line arguments are:\r\n",
      "    0 -> ./a.out\r\n",
      "    1 -> /usr/bin\r\n",
      "    2 -> -a\r\n",
      "    3 -> --human-readable\r\n",
      "    4 -> --color\r\n",
      "    5 -> always\r\n"
     ]
    }
   ],
   "source": [
    "!./a.out /usr/bin -a --human-readable --color always"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "command line arguments are:\r\n",
      "    0 -> ./a.out\r\n",
      "    1 -> /usr/bin/my awesome app dir\r\n",
      "    2 -> -a\r\n",
      "    3 -> --human-readable\r\n",
      "    4 -> --color=always\r\n"
     ]
    }
   ],
   "source": [
    "!./a.out \"/usr/bin/my awesome app dir\" -a --human-readable --color=always"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Готовые решения:\n",
    "\n",
    "* C++, cross-platform [`boost::program_options`](https://www.boost.org/doc/libs/1_58_0/doc/html/program_options.html)\n",
    "* C, unix-only [`getopt`](https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<br />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Замечания после лекции:**\n",
    "* Всё-таки переработать материал про строки, сумбурно и непонятно.\n",
    "* Осталось ~25 минут ещё на лекцию. С этой группой материал идёт быстро. Можно разбавить примерами. Либо материал про чтение из файла и потоки в С++ вынести на первое занятие, оно неплохо тут ложится поверх ввода-вывода."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
